package com.kymatrix.kycarbon.xsmd.system.server.controller;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.kymatrix.kycarbon.xsmd.system.server.model.entity.TenantEntity;
import com.kymatrix.kycarbon.xsmd.system.server.model.entity.UserEntity;
import com.kymatrix.kycarbon.xsmd.system.server.model.form.login.LoginRandomImageResp;
import com.kymatrix.kycarbon.xsmd.system.server.model.form.login.LoginReq;
import com.kymatrix.kycarbon.xsmd.system.server.model.form.login.LoginTokenResp;
import com.kymatrix.kycarbon.xsmd.system.server.model.form.user.TenantIdResp;
import com.kymatrix.kycarbon.xsmd.system.server.service.ITokenService;
import com.kymatrix.kycarbon.xsmd.system.server.service.IUserService;
import com.kymatrix.kycarbon.xsmd.common.business.common.ResultResp;
import com.kymatrix.kycarbon.xsmd.common.exception.BusinessException;
import com.kymatrix.kycarbon.xsmd.common.redis.util.RedisUtil;
import com.kymatrix.kycarbon.xsmd.common.springsecurity.config.SecurityProperties;
import com.kymatrix.kycarbon.xsmd.common.util.Md5Util;
import com.kymatrix.kycarbon.xsmd.common.util.RandImageUtil;
import com.kymatrix.kycarbon.xsmd.system.server.service.ITenantService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.io.IOException;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Api(tags = "用户登录")
@Slf4j
public class LoginController {

    // 特殊标记，用来控制是否校验验证码，redis中存值则表示不校验
    @Value("${security.checkRandomImageKey}")
    private String checkRandomImageKey;

    @Value("${security.signatureSecret}")
    private String signatureSecret;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private IUserService userService;
    @Resource
    private ITenantService tenantService;

    @Resource
    private SecurityProperties securityProperties;
    
    @Resource
    private ITokenService tokenService;

    private static final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";


    /**
     * 获取验证码
     */
    @ApiOperation("获取验证码")
    @GetMapping(value = "/sys/randomImage/{key}")
    public ResultResp<LoginRandomImageResp> randomImage(@PathVariable("key") String key) {
        //生成验证码
        String code = RandomUtil.randomString(BASE_CHECK_CODES, 4);
        //存到redis中
        String lowerCaseCode = code.toLowerCase();

        // 加入密钥作为混淆，避免简单的拼接，被外部利用，用户自定义该密钥即可
        String origin = lowerCaseCode + key;
        String realKey = Md5Util.md5Encode(origin, "utf-8");

        redisUtil.set(realKey, lowerCaseCode, 60);
        log.info("获取验证码，Redis key = {}，checkCode = {}", realKey, code);
        //返回前端
        String base64 = null;
        try {
            base64 = RandImageUtil.generate(code);
        } catch (IOException e) {
            throw new BusinessException("生成验证码出现异常");
        }
        return ResultResp.ok(new LoginRandomImageResp(base64));
    }

    /**
     * 根据租户名称获取租户id
     */
    @ApiOperation("根据租户名称获取租户id")
    @GetMapping("/sys/tenant/getTenantIdByName")
    public ResultResp<TenantIdResp> getTenantIdByName (@RequestParam("name") String name) {
        TenantEntity tenantEntity = tenantService.selectByName(name);
        if (tenantEntity != null) {
            return ResultResp.ok(new TenantIdResp(tenantEntity.getId()));
        }
        return ResultResp.ok();
    }

    /**
     * 用户点击登录并返回token
     */
    @ApiOperation("用户点击登录并返回token")
    @PostMapping("/login/doLogin")
    public ResultResp<LoginTokenResp> doLogin(@RequestBody @Validated LoginReq loginReq) {
        // 校验验证码
        validateCaptcha(loginReq.getCaptcha(), loginReq.getCheckKey());

        UserEntity user = userService.authenticate(loginReq.getUsername(), loginReq.getPassword());

        String token = tokenService.generateToken(user.getId(), loginReq.getAutoLoginFlag());
        
        log.info("用户 {} 登录成功", user.getUsername());
        return ResultResp.ok(LoginTokenResp.builder().token(token).build());
    }

    /**
     * 校验验证码
     */
    private void validateCaptcha(String captcha, String checkKey) {
        String lowerCaseCaptcha = captcha.toLowerCase();
        // 加入密钥作为混淆，避免简单的拼接，被外部利用，用户自定义该密钥即可
        String origin = lowerCaseCaptcha + checkKey + signatureSecret;
        String realKey = Md5Util.md5Encode(origin, "utf-8");
        Object checkCode = redisUtil.get(realKey);
        if (StrUtil.isNotEmpty(checkRandomImageKey)
                && redisUtil.get(checkRandomImageKey) == null
                && StrUtil.isEmptyIfStr(checkCode)) {
            log.error("验证码错误，key={}, checkCode={}, checkCode={}", checkKey, lowerCaseCaptcha, checkCode);
            throw new BusinessException("验证码错误");
        }
        redisUtil.del(realKey);
    }

    /**
     * 退出登录
     */
    @ApiOperation("退出登录")
    @PostMapping("/login/logout")
    public ResultResp<String> logout(HttpServletRequest request) {
        //用户退出逻辑
        String token = request.getHeader(securityProperties.getTokenHeader());
        tokenService.removeToken(token);
        return ResultResp.ok("退出登录成功！");
    }


}
